package lstore

import (
	_ "bytes"
	_ "encoding/binary"
	_ "fmt"
	"localstore/blob"
	"log"
	_ "sync"
	"crypto/md5"
)

const NumPgBmWord = 256
type OsdMeta struct {
	Md5sum   [16]byte
	Version  int64
	Magic    [8]byte		// 'osdmeta '
	NumPg    uint16
	Reserve  [2014]byte
	PgBitmap [NumPgBmWord]uint64
}

// 256MB, the following is the file structure which lay on disk.
// We would never load the whole structure into memory.
type OsdRootDisk struct {
	OsdMeta [NumReplica]OsdMeta
	PgMeta  [NumPgPerOsd * NumReplica]PgMeta
}

type Osd struct {
	id     uint8     // OSD Id
	repIdx int       //which replica of OsdMeta is used now?
	bs     *blob.SpdkBlobStore
	mb     *blob.SpdkBlob //meta blob
	mbId   blob.SpdkBlobId
	meta   *OsdMeta
	pg     map[int]*Pg	//(poolId | PgId)
}

func (o *Osd) getPg(poolId int, pgId int) *Pg {
	id := (poolId<<16) | pgId
	p, ok := o.pg[id]
	if !ok {
		return nil
	}
	return p
}

func (o *Osd) setPg(poolId int, pgId int, p *Pg) {
	id := (poolId<<16) | pgId
	o.pg[id] = p
}

func (o *Osd) createMeta() bool {
	n := (NumPgPerOsd + 1)*NumReplica
	var buf [MetaSize]byte

	for i:=0; i<n; i++ {
		if ok:=blob.SpdkBlobIoWrite(o.mb, buf[0:], int64(i*MetaSize)); !ok {
			log.Printf("SpdkBlobIoWrite error\n")
			return false
		}
	}
	return true
}

func (o *Osd) syncMeta(off int64, meta interface{}) bool {
	buf, ok := Marshal(meta)
	if !ok {
		log.Printf("Marshal error\n")
		return false
	}
	h := md5.New()
	h.Write(buf[16:])
	sum := h.Sum(nil)
	for i:=0; i<16; i++ {
		buf[i] = sum[i]
	}
	if ok:=blob.SpdkBlobIoWrite(o.mb, buf, off); !ok {
		log.Printf("SpdkBlobIoWrite error\n")
		return false
	}
	return true
}

func (o *Osd) syncOsdMeta() bool {
	o.meta.Version ++
	osdmeta := []byte("osdmeta ")
	for i:=0; i<8; i++ {
		o.meta.Magic[i] = osdmeta[i]
	}
	off := int64(o.repIdx * MetaSize)
	ret := o.syncMeta(off, o.meta)
	o.repIdx = (o.repIdx + 1) % NumReplica
	return ret
}

